#第三章:函数：

# 1.求1-100的和
print('求1-100的和:')
sum1 = 0
for i in range(1, 101):
    sum1 += i
print(f'sum1 = {sum1}')  # 5050

# 2.求300-400的和
print('求300-400的和:')
sum2 = 0
for i in range(300, 401):
    sum2 += i
print(f'sum2 = {sum2}')  # 35350

# 3.求1-1000的和
print('求1-1000的和:')
sum3= 0
for i in range(1, 1001):
    sum3 += i
print(f'sum3 = {sum3}')  # 500500


#封装成函数后：
print('封装成函数后:')
def calcSum(begin,end):
    theSum=0
    for i in range(begin,end+1):
        theSum+=i
    return theSum
print(calcSum(1,100))
print(calcSum(300,400))
print(calcSum(1,1000))

#Python是动态类型语言，函数的形参和返回值都不必指定类型，因此一个函数可以支持多种不同类型的参数。
#Python中的一个函数可以有一个或多个返回值，当有多个值需要返回时，使用,来分隔这多个返回值。比如：


def getSumAndDif(x, y):
    return x + y, x - y

a=10
b=20
sum, dif = getSumAndDif(a, b)
print(f'{a} + {b} = {sum}, {a} - {b} = {dif}')

dif2,sum2=getSumAndDif(a,b)
print(f'{a} + {b} = {sum2}, {a} - {b} = {dif2}')

#调用是根据返回的先后顺序来进行匹配：

#Python中一个函数能返回多个值，本质就是多元赋值所支持的。如果函数调用者只想关注该函数的部分返回值，
#那么可以使用_来忽略不想要的返回值。比如：
_, dif3 = getSumAndDif(1, 2)
print(dif3)


#调用函数时可以根据函数的形参列表，将实参列表中的实参按照顺序依次传给对应的形参。比如：
def Dif(x, y):
    return x - y

print('传参1:')
print(Dif(10, 20))  # -10
print('传参2:')
#也可以通过关键字参数来调整传参的顺序，显式指定当前实参传递给哪个形参。比如：
print(Dif(x=10,y=20))

#函数调用：
#链式调用：
print('链式调用:')
def Add(x,y):
    return x+y
print(Add(10,20))
#嵌套调用:
print('嵌套调用:')
def test():
    print('do something')
    print('do something')
    print('do somethong')

test()
#递归调用:
def factor(n):
    if n==1:
        return 1
    return n*factor(n-1)
print(factor(6))


#默认参数：
#可以给函数的形参指定默认值，在调用函数时可以不必给带有默认值的形参传参，此时该形参将会使用我们指定的默认值。
#下面调用Add函数时如果不传入第二个参数，则默认返回第一个参数与1的和，如果调用Add函数时传入了第二个参数，则返回这两个参数的和。
print('默认参数:')
def Add2(data, val=1):
    return data + val


print(Add2(10))     # 11
print(Add2(10, 2))  # 12
#注意： 在定义函数时，带有默认值的参数需要放到没有默认值的参数后面。

#变长参数：
#如果想让函数接收任意个数的参数，可以在函数定义的形参名称前面添加*，
#这时函数将接收一个参数元组，并且我们可以以形参名[下标]的方式相应地访问传入的各个实参。比如：
print('变长参数:')
def Func(*arg):
    n = len(arg)
    for i in range(n):
        print(arg[i])
Func(1)
Func(1, 2, 3)

#变量作用域：
#需要注意的是，如果在函数内部尝试访问的变量在局部不存在，就会尝试去全局域中查找。比如：
print('全局变量：')
x = 10

def Func2():
    print(f'x = {x}')

Func2()  # x = 10


#但如果想要在函数内部修改全局变量的值，就需要使用global关键字进行声明。比如：
print('修改全局变量：')
def Func3():
    global x  # 声明
    x = 20
    print(f'函数内部: x = {x}')  # x = 20

Func3()
print(f'函数外部: x = {x}')  # x = 20

#如果在函数内部修改全局变量时没有用global关键字进行声明，
#那么此时Python解释器会认为你是想在函数内部创建一个同名的局部变量，此时你的修改操作就不会影响到对应的全局变量。比如：
m=50
print('不用global关键字进行声明')
def Func4():
    # global x
    m = 20
    print(f'函数内部: m = {m}')  # 20

Func4()
print(f'函数外部: m = {m}')  # x50
#if、while、for中的变量:
#Python中的if、while、for等语句块不会影响变量的作用域，因此在这些语句块中定义的变量，也能在外面正常使用。比如：
print('if while for中的变量:')
for i in range(10):
    print(f'函数内部: i = {i}')

print(f'函数外部: i = {i}')  # i = 9

